// 该文件封装 TinyMCE 富文本内图片的预览控制逻辑：
// - 负责创建/销毁预览浮层 DOM 结构（关闭按钮 + 大图 + 工具栏）
// - 管理缩放、拖动、旋转、镜像等变换状态
// - 对外只暴露 show / hide / destroy 三个方法，指令层只需调用 show 即可
import angular from 'angular';

// 缩放相关常量
const PREVIEW_MIN_ZOOM = 0.5;
const PREVIEW_MAX_ZOOM = 4;
const PREVIEW_ZOOM_STEP = 0.25;
const PREVIEW_ZOOM_KEYS = {
  '+': PREVIEW_ZOOM_STEP,
  '-': -PREVIEW_ZOOM_STEP,
  '=': PREVIEW_ZOOM_STEP,
  '_': -PREVIEW_ZOOM_STEP
};

export default function createImagePreviewController($window, $document) {
  let overlayEl = null;
  let imageEl = null;
  let captionEl = null;
  let closeBtnEl = null;
  let toolbarEl = null;
  let zoomInBtn = null;
  let zoomOutBtn = null;
  let zoomResetBtn = null;
  let visible = false;
  let keydownHandler = null;

  let zoom = 1;
  let rotation = 0;
  let flipX = 1;
  let flipY = 1;
  let position = { x: 0, y: 0 };
  let dragActive = false;
  let dragStartPoint = null;
  let dragOrigin = null;
  let momentumFrame = null;

  // 从事件对象中抽取客户端坐标，统一处理鼠标和触摸
  function getPointerPosition(event) {
    if (event.touches && event.touches.length) {
      const touch = event.touches[0];
      return {
        x: touch.clientX,
        y: touch.clientY
      };
    }

    return {
      x: event.clientX,
      y: event.clientY
    };
  }

  // 只在图片被放大后允许拖动
  function isDraggable() {
    return zoom > 1;
  }

  // 根据是否拖动中切换鼠标样式
  function setDraggingCursor(active) {
    if (!imageEl) {
      return;
    }

    if (!isDraggable()) {
      imageEl.style.cursor = zoom > 1 ? 'grab' : 'default';
      return;
    }

    imageEl.style.cursor = active ? 'grabbing' : 'grab';
  }

  // 解绑文档上的拖动相关监听
  function detachDragListeners() {
    $document.off('mousemove', handlePointerMove);
    $document.off('touchmove', handlePointerMove);
    $document.off('mouseup', handlePointerUp);
    $document.off('touchend', handlePointerUp);
    $document.off('touchcancel', handlePointerUp);
  }

  // 拖动起始：记录起点和原始位移
  function handlePointerDown(event) {
    if (!isDraggable()) {
      return;
    }

    event.preventDefault();

    dragActive = true;
    dragStartPoint = getPointerPosition(event);
    dragOrigin = { x: position.x, y: position.y };
    setDraggingCursor(true);

    $document.on('mousemove', handlePointerMove);
    $document.on('touchmove', handlePointerMove);
    $document.on('mouseup', handlePointerUp);
    $document.on('touchend', handlePointerUp);
    $document.on('touchcancel', handlePointerUp);
  }

  // 拖动过程中实时更新 position 并渲染 transform
  function handlePointerMove(event) {
    if (!dragActive) {
      return;
    }

    event.preventDefault();

    const point = getPointerPosition(event);
    const delta = {
      x: point.x - dragStartPoint.x,
      y: point.y - dragStartPoint.y
    };

    position = {
      x: dragOrigin.x + delta.x,
      y: dragOrigin.y + delta.y
    };

    renderTransform();
  }

  // 拖动结束：解绑事件并做一次边界修正
  function handlePointerUp() {
    if (!dragActive) {
      return;
    }

    dragActive = false;
    setDraggingCursor(false);
    detachDragListeners();
    applyTransform({ ensureBounds: true });
  }

  // 确保预览浮层只创建一次
  function ensureOverlay() {
    if (overlayEl) {
      return;
    }

    const doc = $document[0];
    overlayEl = doc.createElement('div');
    overlayEl.className = 'ng-tinymce-image-preview-overlay';
    overlayEl.innerHTML =
      '<button type="button" class="ng-tinymce-image-preview-close">×</button>' +
      '<div class="ng-tinymce-image-preview-dialog">' +
      '<div class="ng-tinymce-image-preview-body"><img alt="" /></div>' +
      '<div class="ng-tinymce-image-preview-caption"></div>' +
      '</div>' +
      '<div class="ng-tinymce-image-preview-toolbar">' +
      '<button type="button" data-action="zoom-out">－</button>' +
      '<button type="button" data-action="zoom-in">＋</button>' +
      '<button type="button" data-action="zoom-reset">1:1</button>' +
      '<button type="button" data-action="rotate-left">↺</button>' +
      '<button type="button" data-action="rotate-right">↻</button>' +
      '<button type="button" data-action="flip-horizontal">⇋</button>' +
      '<button type="button" data-action="flip-vertical">⇵</button>' +
      '<button type="button" data-action="reset">重置</button>' +
      '</div>';

    imageEl = overlayEl.querySelector('img');
    captionEl = overlayEl.querySelector('.ng-tinymce-image-preview-caption');
    closeBtnEl = overlayEl.querySelector('.ng-tinymce-image-preview-close');
    toolbarEl = overlayEl.querySelector('.ng-tinymce-image-preview-toolbar');
    zoomInBtn = toolbarEl.querySelector('[data-action="zoom-in"]');
    zoomOutBtn = toolbarEl.querySelector('[data-action="zoom-out"]');
    zoomResetBtn = toolbarEl.querySelector('[data-action="zoom-reset"]');

    imageEl.addEventListener('mousedown', handlePointerDown);
    imageEl.addEventListener('touchstart', handlePointerDown);
    imageEl.addEventListener('wheel', handleWheel, { passive: false });
    imageEl.addEventListener('dblclick', handleDoubleClick);

    overlayEl.addEventListener('click', function(event) {
      if (event.target === overlayEl) {
        hide();
      }
    });

    closeBtnEl.addEventListener('click', function(event) {
      event.preventDefault();
      hide();
    });

    toolbarEl.addEventListener('click', function(event) {
      const button = event.target.closest('button');
      if (!button) {
        return;
      }

      const action = button.getAttribute('data-action');
      if (!action) {
        return;
      }

      event.preventDefault();
      handleToolbarAction(action);
    });

    doc.body.appendChild(overlayEl);
  }

  // 获取视口尺寸，用于边界修正
  function getViewportSize() {
    const doc = $document[0];
    const docEl = doc.documentElement;
    return {
      width: $window.innerWidth || docEl.clientWidth,
      height: $window.innerHeight || docEl.clientHeight
    };
  }

  // 根据当前缩放比更新工具栏按钮状态，并刷新拖动指针形态
  function updateToolbarState() {
    if (zoomInBtn && zoomOutBtn && zoomResetBtn) {
      zoomInBtn.disabled = zoom >= PREVIEW_MAX_ZOOM - 0.01;
      zoomOutBtn.disabled = zoom <= PREVIEW_MIN_ZOOM + 0.01;
      zoomResetBtn.disabled = zoom === 1;
    }

    setDraggingCursor(false);
  }

  // 把当前位移/旋转/缩放同步到图片元素上
  function renderTransform() {
    if (!imageEl) {
      return;
    }

    imageEl.style.transform =
      'translate(' +
      position.x +
      'px, ' +
      position.y +
      'px) rotate(' +
      rotation +
      'deg) scale(' +
      zoom * flipX +
      ', ' +
      zoom * flipY +
      ')';

    updateToolbarState();
  }

  // 检查当前图片是否超出视口范围，必要时自动回弹到可视区域
  function fixPositionIfNeeded() {
    if (!imageEl) {
      return;
    }

    const rect = imageEl.getBoundingClientRect();
    const viewport = getViewportSize();
    let adjustX = 0;
    let adjustY = 0;

    if (rect.width <= viewport.width) {
      adjustX = viewport.width / 2 - (rect.left + rect.width / 2);
    } else {
      if (rect.left > 0) {
        adjustX = -rect.left;
      } else if (rect.right < viewport.width) {
        adjustX = viewport.width - rect.right;
      }
    }

    if (rect.height <= viewport.height) {
      adjustY = viewport.height / 2 - (rect.top + rect.height / 2);
    } else {
      if (rect.top > 0) {
        adjustY = -rect.top;
      } else if (rect.bottom < viewport.height) {
        adjustY = viewport.height - rect.bottom;
      }
    }

    if (Math.abs(adjustX) > 0.5 || Math.abs(adjustY) > 0.5) {
      position = {
        x: position.x + adjustX,
        y: position.y + adjustY
      };

      renderTransform();
    }
  }

  // 统一执行变换：先渲染，再按需修正边界
  function applyTransform(options) {
    const opts = options || {};
    renderTransform();

    if (!dragActive && opts.ensureBounds !== false) {
      fixPositionIfNeeded();
    }
  }

  // 在指定缩放目标值、可选的缩放中心下更新 zoom 与 position
  function applyZoom(nextScale, origin) {
    const target = Math.max(PREVIEW_MIN_ZOOM, Math.min(PREVIEW_MAX_ZOOM, nextScale));
    if (target === zoom) {
      return;
    }

    if (origin && imageEl) {
      const rect = imageEl.getBoundingClientRect();
      const centerX = rect.left + rect.width / 2;
      const centerY = rect.top + rect.height / 2;
      const offsetX = origin.x - centerX;
      const offsetY = origin.y - centerY;
      const scaleRatio = target / zoom;
      position = {
        x: position.x - offsetX * (scaleRatio - 1),
        y: position.y - offsetY * (scaleRatio - 1)
      };
    } else if (target <= 1 && rotation % 360 === 0 && flipX === 1 && flipY === 1) {
      position = { x: 0, y: 0 };
    }

    zoom = target;
    applyTransform();
  }

  // 按固定比例增减缩放
  function adjustZoom(delta) {
    const ratio = delta >= 0 ? 1 + Math.abs(delta) : 1 / (1 + Math.abs(delta));
    applyZoom(zoom * ratio);
  }

  // 围绕特定坐标点做缩放（用于滚轮和双击）
  function zoomAtPoint(delta, clientX, clientY) {
    const ratio = delta >= 0 ? 1 + Math.abs(delta) : 1 / (1 + Math.abs(delta));
    applyZoom(zoom * ratio, { x: clientX, y: clientY });
  }

  // 顺/逆时针旋转一定角度
  function rotate(delta) {
    rotation = (rotation + delta) % 360;
    if (rotation < 0) {
      rotation += 360;
    }

    if (zoom <= 1 && rotation % 360 === 0 && flipX === 1 && flipY === 1) {
      position = { x: 0, y: 0 };
    }

    applyTransform();
  }

  // 水平/垂直镜像
  function flip(axis) {
    if (axis === 'horizontal') {
      flipX = flipX === 1 ? -1 : 1;
    } else if (axis === 'vertical') {
      flipY = flipY === 1 ? -1 : 1;
    }

    applyTransform();
  }

  // 将所有变换重置为初始状态
  function resetTransform() {
    zoom = 1;
    rotation = 0;
    flipX = 1;
    flipY = 1;
    position = { x: 0, y: 0 };
    if (momentumFrame) {
      $window.cancelAnimationFrame(momentumFrame);
      momentumFrame = null;
    }

    applyTransform({ ensureBounds: false });
  }

  // 键盘事件：Esc 关闭，+/- 控制缩放步进
  function handleKeydown(event) {
    if (event.key === 'Escape') {
      event.preventDefault();
      hide();
      return;
    }

    const zoomDelta = PREVIEW_ZOOM_KEYS[event.key];
    if (zoomDelta) {
      event.preventDefault();
      adjustZoom(zoomDelta);
    }
  }

  // 鼠标滚轮控制缩放（向上放大，向下缩小）
  function handleWheel(event) {
    event.preventDefault();

    const delta = event.deltaY > 0 ? -PREVIEW_ZOOM_STEP : PREVIEW_ZOOM_STEP;
    zoomAtPoint(delta, event.clientX, event.clientY);
  }

  // 双击在当前位置放大 / 还原
  function handleDoubleClick(event) {
    if (zoom !== 1 || rotation !== 0 || flipX !== 1 || flipY !== 1) {
      resetTransform();
      return;
    }

    zoomAtPoint(PREVIEW_ZOOM_STEP, event.clientX, event.clientY);
  }

  // 底部工具栏按钮映射到对应操作
  function handleToolbarAction(action) {
    switch (action) {
      case 'zoom-in':
        adjustZoom(PREVIEW_ZOOM_STEP);
        break;
      case 'zoom-out':
        adjustZoom(-PREVIEW_ZOOM_STEP);
        break;
      case 'zoom-reset':
        applyZoom(1);
        break;
      case 'rotate-left':
        rotate(-90);
        break;
      case 'rotate-right':
        rotate(90);
        break;
      case 'flip-horizontal':
        flip('horizontal');
        break;
      case 'flip-vertical':
        flip('vertical');
        break;
      case 'reset':
        resetTransform();
        break;
      default:
        break;
    }
  }

  // 对外暴露：显示预览
  function show(src, caption) {
    ensureOverlay();

    imageEl.setAttribute('src', src);
    imageEl.setAttribute('alt', caption || '');
    captionEl.textContent = caption || '';
    resetTransform();

    overlayEl.classList.add('is-visible');
    visible = true;

    keydownHandler = handleKeydown;
    $document.on('keydown', keydownHandler);
  }

  // 对外暴露：隐藏预览但不销毁 DOM
  function hide() {
    if (!overlayEl || !visible) {
      return;
    }

    overlayEl.classList.remove('is-visible');
    visible = false;

    if (keydownHandler) {
      $document.off('keydown', keydownHandler);
      keydownHandler = null;
    }

    detachDragListeners();
    if (momentumFrame) {
      $window.cancelAnimationFrame(momentumFrame);
      momentumFrame = null;
    }
    setDraggingCursor(false);
  }

  // 对外暴露：销毁预览浮层和所有监听
  function destroy() {
    hide();

    if (overlayEl && overlayEl.parentNode) {
      overlayEl.parentNode.removeChild(overlayEl);
    }

    if (imageEl) {
      imageEl.removeEventListener('mousedown', handlePointerDown);
      imageEl.removeEventListener('touchstart', handlePointerDown);
      imageEl.removeEventListener('wheel', handleWheel);
      imageEl.removeEventListener('dblclick', handleDoubleClick);
    }

    detachDragListeners();
    if (momentumFrame) {
      $window.cancelAnimationFrame(momentumFrame);
      momentumFrame = null;
    }

    overlayEl = null;
    imageEl = null;
    captionEl = null;
    closeBtnEl = null;
    toolbarEl = null;
    zoomInBtn = null;
    zoomOutBtn = null;
    zoomResetBtn = null;
  }

  return {
    show,
    hide,
    destroy
  };
}
